Add new format "g7towin". This format can read data files (.g7t) from G7ToWin.
authoroliskoli <oliskoli>
Sun, 15 Apr 2007 19:46:05 +0000 (19:46 +0000)
committeroliskoli <oliskoli>
Sun, 15 Apr 2007 19:46:05 +0000 (19:46 +0000)
g7towin.c [new file with mode: 0644]

diff --git a/g7towin.c b/g7towin.c
new file mode 100644 (file)
index 0000000..4160977
--- /dev/null
+++ b/g7towin.c
@@ -0,0 +1,541 @@
+/*
+
+    Support for G7ToWin data files (.g7t),
+    Copyright (C) 2007 Olaf Klein, o.b.klein@gpsbabel.org
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA
+*/
+
+/*
+    History:
+               04/07/2007: start programming
+*/
+
+#include "defs.h"
+#include "csv_util.h"
+#include "garmin_fs.h"
+#include "garmin_tables.h"
+#include "jeeps/gpsmath.h"
+#include "strptime.h"
+
+#include <time.h>
+
+#if CSVFMTS_ENABLED
+
+#define MYNAME "g7towin"
+
+#define G7T_HEADER     "Version 2:G7T"
+
+static gbfile *fin;
+static grid_type grid;
+static int datum;
+static gpsdata_type mode;
+static double altf;
+static int gardown;
+static int event_ct;
+
+static
+arglist_t g7towin_args[] = {
+       ARG_TERMINATOR
+};
+
+#define WAYPT__OFS     0x00000
+#define TRKPT__OFS     0x01000
+
+#define WPT_c0_OFS     0x0c000
+#define WPT_c1_OFS     0x0c100
+#define WPT_c2_OFS     0x0c200
+#define WPT_c3_OFS     0x0c300
+#define WPT_c4_OFS     0x0c400
+#define WPT_c5_OFS     0x0c500
+#define WPT_c6_OFS     0x0c600
+#define WPT_c7_OFS     0x0c700
+#define WPT_c8_OFS     0x0c800
+#define WPT_cA_OFS     0x0cA00
+#define WPT_cB_OFS     0x0cB00
+#define WPT_cC_OFS     0x0cC00
+#define WPT_cD_OFS     0x0cD00
+
+static void
+parse_line(char *buff, int index, const char *delimiter, waypoint *wpt)
+{
+       char *cin;
+       garmin_fs_p gmsd = GMSD_FIND(wpt);
+
+       while ((cin = csv_lineparse(buff, delimiter, "", index++))) {
+
+               buff = NULL;
+               cin = lrtrim(cin);
+               
+               if ((*cin == '\0') || 
+                   (strcmp(cin, "INF") == 0) ||
+                   (strcmp(cin, "1e25") == 0) ||
+                   (strcmp(cin, "1.0e25") == 0)) continue;
+               
+               switch(index) {
+
+                       int categories, dyn;
+                       struct tm tm;
+                       char *cerr;
+                       
+                       case TRKPT__OFS + 1:
+                               cin += parse_coordinates(cin, datum, grid,
+                                       &wpt->latitude, &wpt->longitude, MYNAME);
+                               while (isspace(*cin)) cin++;
+                               
+                               memset(&tm, 0, sizeof(tm));
+                               cerr = strptime(cin, "%a %b %d %H:%M:%S %Y", &tm);
+                               if (cerr == NULL) {
+                                       fatal(MYNAME ": Unable to convert date (%s)!\n", cin);
+                               }
+                               wpt->creation_time = mkgmtime(&tm);
+                               break;
+                               
+                       case WAYPT__OFS + 1: 
+                               wpt->description = xstrdup(cin); 
+                               break;
+
+                       case WAYPT__OFS + 2:
+                               wpt->icon_descr = gt_find_desc_from_icon_number(
+                                       atoi(cin), PCX, &dyn);
+                               wpt->wpt_flags.icon_descr_is_dynamic = dyn;
+                               break;
+
+                       case WAYPT__OFS + 4:
+                               if (strcmp(cin, "S+C") == 0) {
+                                       GMSD_SET(display, gt_display_mode_symbol_and_comment);
+                               }
+                               else if (strcmp(cin, "S") == 0) {
+                                       GMSD_SET(display, gt_display_mode_symbol);
+                               }
+                               else if (strcmp(cin, "S+N") == 0) {
+                                       GMSD_SET(display, gt_display_mode_symbol_and_name);
+                               }
+                               break;
+
+                       case WPT_cA_OFS + 1:
+                       case WPT_c1_OFS + 1:
+                               if (wpt->shortname) xfree(wpt->shortname);
+                               wpt->shortname = xstrdup(cin);
+                               break;
+
+                       case WPT_cA_OFS + 4:
+                       case WPT_c4_OFS + 2:
+                               GMSD_SETSTR(city, cin);
+                               break;
+
+                       case WPT_cA_OFS + 5:
+                       case WPT_c4_OFS + 3:
+                               GMSD_SETSTR(state, cin);
+                               break;
+
+                       case WPT_cA_OFS + 6:
+                       case WPT_c4_OFS + 4:
+                               GMSD_SETSTR(cc, cin);
+                               break;
+
+                       case WPT_cB_OFS + 1:
+                       case WPT_c6_OFS + 2:
+                               GMSD_SETSTR(facility, cin);
+                               break;
+
+                       case WPT_cB_OFS + 2:
+                       case WPT_c6_OFS + 3:
+                               GMSD_SETSTR(addr, cin);
+                               break;
+
+                       case WPT_cB_OFS + 3: /*cross road */
+                       case WPT_c6_OFS + 4:
+                               GMSD_SETSTR(cross_road, cin);
+                               break;
+
+                       case TRKPT__OFS + 2: /* altitude */
+                       case WPT_cC_OFS + 1:
+                       case WPT_c5_OFS + 1:
+                       case WPT_c8_OFS + 1:
+                               wpt->altitude = altf * atof(cin);
+                               break;
+
+                       case TRKPT__OFS + 3: /* depth */
+                       case WPT_cC_OFS + 2:
+                       case WPT_c5_OFS + 2:
+                       case WPT_c8_OFS + 2:
+                               GMSD_SET(depth, altf * atof(cin));
+                               break;
+                               
+                       case TRKPT__OFS + 10: /* temperature */
+                               if (*cin == '|') cin++; /* in track points */
+                               if (strcmp(cin, "1e25") == 0) break;
+                               if (strcmp(cin, "1.0e25") == 0) break;
+                               /* !!! NO BREAK !!! */
+                       case WPT_cD_OFS + 1:
+                       case WPT_cB_OFS + 6:
+                               GMSD_SET(temperature, atof(cin));
+                               break;
+
+                       case WAYPT__OFS + 6: /* proximity */
+                       case WPT_cD_OFS + 2:
+                               GMSD_SET(proximity, atof(cin));
+                               break;
+
+                       case WPT_cB_OFS + 5: 
+                       case WPT_cD_OFS + 3:
+                               categories = atoi(cin);
+                               if (categories != 0)
+                                       GMSD_SET(category, atoi(cin));
+                               break;
+                               
+#if 0
+
+/* currently unused */
+
+                       case TRKPT__OFS + 5: /* distance from previous point */
+                       case TRKPT__OFS + 6: /* distance from segment start */
+                       case TRKPT__OFS + 7: /* distance from start */
+                       case TRKPT__OFS + 8: /* velocity from previous point */
+                       case TRKPT__OFS + 9: /* time (in seconds) from previous point */
+                               break;
+
+                       case WAYPT__OFS + 3: /* ignore color */
+                               break;
+
+                       case WAYPT__OFS + 5: /* always '0' */
+                               break;
+
+                       case TRKPT__OFS + 4:
+                               if (case_ignore_strcmp(cin, "FT") == 0) ;
+                               else if (case_ignore_strcmp(cin, "M") == 0) ;
+                               else if (case_ignore_strcmp(cin, "SM") == 0) ;
+                               else if (case_ignore_strcmp(cin, "NM") == 0) ;
+                               else if (case_ignore_strcmp(cin, "KM") == 0) ;
+                               break;
+
+                       case WPT_cB_OFS + 4: /* unknown (datatype) */
+                               break;
+
+                       case WPT_cC_OFS + 3: /* waypt_class (always FF) */
+                               break;
+
+                       case WPT_cC_OFS + 4: /* class & subclass */
+                       case WPT_cC_OFS + 5: 
+                       case WPT_cC_OFS + 6:
+                       case WPT_cC_OFS + 7: 
+                       case WPT_cC_OFS + 8: 
+                       case WPT_cC_OFS + 9: 
+                       case WPT_cC_OFS + 10:
+                       case WPT_cC_OFS + 11: 
+                       case WPT_cC_OFS + 12: 
+                       case WPT_cC_OFS + 13: 
+                       case WPT_cC_OFS + 14:
+                       case WPT_cC_OFS + 15: 
+                       case WPT_cC_OFS + 16: 
+                       case WPT_cC_OFS + 17: 
+                       case WPT_cC_OFS + 18:
+                       case WPT_cC_OFS + 19: 
+                       case WPT_cC_OFS + 20: 
+                       case WPT_cC_OFS + 21: 
+                               break;
+
+                       case WPT_cC_OFS + 22:
+                               /* distance */
+                               break;
+#endif
+               }
+       }
+}
+
+static waypoint *
+parse_waypt(char *buff)
+{
+       char *cin, *cerr;
+       int i;
+       struct tm tm;
+       waypoint *wpt;
+       garmin_fs_p gmsd;
+       
+       wpt = waypt_new();
+       gmsd = garmin_fs_alloc(-1);
+       fs_chain_add(&wpt->fs, (format_specific_data *) gmsd);
+       
+       if (gardown)
+               cin = buff + 6;
+       else
+               cin = buff + 15;
+
+       while (isspace(*cin)) cin--;
+       if (cin >= buff)
+               wpt->shortname = xstrndup(buff, cin - buff + 1);
+
+       if (gardown)
+               buff += 7;
+       else
+               buff += 16;
+
+       buff += parse_coordinates(buff, datum, grid,
+               &wpt->latitude, &wpt->longitude, MYNAME);
+       while (isspace(*buff)) buff++;
+
+       memset(&tm, 0, sizeof(tm));
+       cerr = strptime(buff, "%a %b %d %H:%M:%S %Y", &tm);
+       if (cerr == NULL)
+               fatal(MYNAME ": Unable to convert date (%s)!\n", buff);
+       wpt->creation_time = mkgmtime(&tm);
+       
+       /* go over time stamp */
+       i = 5;
+       while (buff && i) {
+               i--;
+               buff = strchr(buff, ' ');
+               if (buff) buff++;
+       }
+       if (gardown && (buff == NULL)) return wpt;
+       is_fatal((buff == NULL), MYNAME ": Incomplete waypoint line!");
+
+       while (isspace(*buff)) buff++;
+
+       parse_line(buff, WAYPT__OFS, "^", wpt);
+
+       return wpt;
+}
+
+static waypoint *
+parse_trkpt(char *buff)
+{
+       garmin_fs_p gmsd;
+       waypoint *wpt;
+       
+       wpt = waypt_new();
+       gmsd = garmin_fs_alloc(-1);
+       fs_chain_add(&wpt->fs, (format_specific_data *) gmsd);
+       
+       parse_line(buff, TRKPT__OFS, ";", wpt);
+       
+       return wpt;
+}
+
+/*
+ * parse_categories is currently only a dummy procedure.
+ * w'll need a central storage with binding to the module
+ * which has established a list of category names.
+ */
+static void
+parse_categories(char *buff)
+{
+       char *cin;
+       int cat = 0;
+       
+       while ((cin = csv_lineparse(buff, ",", "", cat++))) {
+               gbuint16 cx;
+               
+               buff = NULL;
+               
+               cin = lrtrim(cin);
+               if (*cin == 0) continue;
+               
+               garmin_fs_convert_category(cin, &cx);
+       }
+}
+
+
+/* main functions */
+
+static void
+rd_init(const char *fname)
+{
+       fin = gbfopen(fname, "rb", MYNAME);
+       
+       gardown = 1;
+       mode = wptdata;
+       grid = grid_lat_lon_dmm;
+       datum = DATUM_WGS84;
+       altf = 1;
+       event_ct = 0;
+}
+
+static void
+rd_deinit(void)
+{
+       gbfclose(fin);
+}
+
+static void
+data_read(void)
+{
+       char *buff;
+       int line = 0;
+       waypoint *wpt = NULL;
+       waypoint *prev = NULL;
+       route_head *head = NULL;
+       
+       while ((buff = gbfgetstr(fin))) {
+               char *cin = buff;
+               char *cdata;
+               
+               line++;
+               
+               cin = lrtrim(buff);
+               if (!*cin) continue;
+               
+               cdata = cin+1;
+               while (! isspace(*cdata)) cdata++;
+               while (isspace(*cdata)) cdata++;
+               if (! *cdata) continue;
+               
+               switch(*cin) {
+
+               case '#': /* comment */
+                       break;
+                       
+               case 'A':
+                       if (case_ignore_strncmp(cdata, "Meter", 5) == 0)
+                               altf = 1.0;
+                       else if (case_ignore_strncmp(cdata, "Feet", 4) == 0)
+                               altf = FEET_TO_METERS(1.0);
+                       break;
+
+               case 'C': /* categories */
+                       parse_categories(cdata);
+                       break;
+
+               case 'D':
+                       datum = gt_lookup_datum_index(cdata, MYNAME);
+                       break;
+
+               case 'I': /* event point */
+                       wpt = waypt_new();
+                       cdata += parse_coordinates(cdata, datum, grid,
+                               &wpt->latitude, &wpt->longitude, MYNAME);
+                       xasprintf(&wpt->shortname, "Event%d", ++event_ct);
+                       while (isspace(*cdata)) cdata++;
+                       if (*cdata == ';') {
+                               int dyn;
+                               
+                               cdata++;
+                               wpt->icon_descr = gt_find_desc_from_icon_number(
+                                       atoi(cdata), PCX, &dyn);
+                               wpt->wpt_flags.icon_descr_is_dynamic = dyn;
+                       }
+                       waypt_add(wpt);
+                       break;
+                       
+               case 'M':
+                       grid = gt_lookup_grid_type(cdata, MYNAME);
+                       break;
+
+               case 'P': /* proximity waypoint */
+               case 'W': /* normal waypoint */
+                       wpt = parse_waypt(cdata);
+                       prev = wpt;
+                       if (wpt) {
+                               if (mode == rtedata)
+                                       route_add_wpt(head, wpt);
+                               else
+                                       waypt_add(wpt);
+                       }
+                       break;
+
+               case 'c': /* additional lines */
+                       switch(*(cin+1)) {
+                       int index;
+                       
+                       case 'A': case 'B':
+                       case 'C': case 'D':
+                               
+                               index = WPT_cA_OFS + ((*(cin+1) - 'A') * 256);
+                               parse_line(cdata, index, "|", wpt);
+                               break;
+                               
+                       case '1': case '2': case '3': case '4':
+                       case '5': case '6': case '7': case '8':
+                       
+                               index = WPT_c0_OFS + ((*(cin+1) - '0') * 256);
+                               parse_line(cdata, index, ";", wpt);
+                               break;
+                               
+                       case 'L':
+                               waypt_add_url(wpt, xstrdup(cdata), NULL);
+                               break;
+
+                       default:
+                               break;
+                       }
+                       break;
+                       
+               case 'N':       /* track log header */
+                       mode = trkdata;
+                       head = route_head_alloc();
+                       cdata = strchr(cdata, '-');
+                       if (cdata) {
+                               while (isspace(*cdata)) cdata++;
+                               if (*cdata) {
+                                       char *s;
+                                       s = strrchr(cdata, ',');
+                                       if (s) {
+                                               *s = '\0';
+                                               s = strrchr(cdata, ',');
+                                               if (s) {
+                                                       *s = '\0';
+                                                       head->rte_name = xstrdup(cdata);
+                                               }
+                                       }
+                               }
+                       }
+                       track_add_head(head);
+                       break;
+
+               case 'R':       /* route header */
+                       mode = rtedata;
+                       head = route_head_alloc();
+                       cdata += 3; /*skip route number */
+                       if (*cdata) head->rte_name = xstrdup(cdata);
+                       route_add_head(head);
+                       break;
+
+               case 'T':
+                       wpt = parse_trkpt(cdata);
+                       if (wpt) track_add_wpt(head, wpt);
+                       break;
+                       
+               case 'V':
+                       if (strcmp(cin, G7T_HEADER) != 0) {
+                               fatal(MYNAME ": Invalid version or invalid file!\n");
+                       }
+                       gardown = 0;
+                       break;
+
+               default:
+                       break;
+               }
+       }
+}
+
+/* --------------------------------------------------------------------------- */
+
+ff_vecs_t g7towin_vecs = {
+       ff_type_file,
+       { ff_cap_read, ff_cap_read, ff_cap_read },
+       rd_init,
+       NULL,
+       rd_deinit,
+       NULL,
+       data_read,
+       NULL,
+       NULL,
+       g7towin_args,
+       CET_CHARSET_MS_ANSI, 0
+};
+
+#endif /* CSVFMTS_ENABLED */